package com.retry.task.admin.filter;

import java.io.IOException;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.common.collect.Sets;
import com.retry.task.admin.constants.Constants;
import com.retry.task.admin.biz.service.UserInfoBizService;
import com.retry.task.admin.dal.model.UserInfoDO;
import com.retry.task.admin.session.SessionInfo;
import com.retry.task.admin.threadlocal.SessionThreadLocalService;
import com.retry.task.admin.threadlocal.ThreadLocalManager;
import com.retry.task.admin.utils.AesUtils;
import com.retry.task.admin.utils.FilterUtils;
import com.retry.task.core.model.base.Result;
import com.retry.task.core.utils.GsonTool;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author gao.gwq
 * @version 1.0
 * @date 2022/6/12  23:40
 * @Description TODO
 */
public class LoginFilter implements Filter {

    private static Logger LOGGER = LoggerFactory.getLogger(LoginFilter.class);

    private UserInfoBizService userInfoService;

    public static final String WHITE_LIST = "whitelist";

    public static final String LOGIN_URL = "loginURL";

    public static final String LOGIN_API = "loginApi";

    private Set<String> whiteList = Sets.newHashSet();

    private String loginURL;

    private String loginApi;

    public void setUserInfoService(UserInfoBizService userInfoService) {
        this.userInfoService = userInfoService;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        loginURL = filterConfig.getInitParameter(LOGIN_URL);

        loginApi = filterConfig.getInitParameter(LOGIN_API);

        String whilteListStr = filterConfig.getInitParameter(WHITE_LIST);
        if (StringUtils.isNotBlank(whilteListStr)) {
            String[] splitWhiteStr = whilteListStr.split(",");

            for (String whiteStr : splitWhiteStr) {
                whiteList.add(whiteStr.trim());
            }
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
        throws IOException, ServletException {

        if (!(request instanceof HttpServletRequest && response instanceof HttpServletResponse)) {
            filterChain.doFilter(request, response);
            return;
        }

        final HttpServletRequest httpRequest = (HttpServletRequest)request;
        final HttpServletResponse httpResponse = (HttpServletResponse)response;
        final String requestURI = httpRequest.getRequestURI();
        final String requestURL = httpRequest.getRequestURL().toString();

        // 白名单匹配, *代表任意字符， ?代表单个字符
        // abc , a* true
        // abc, a?c  true
        // abc, a*  true
        // abcd, a*c  false
        if (FilterUtils.isInWhiteList(whiteList, requestURI)) {
            filterChain.doFilter(request, response);
            return;
        }
        if (StringUtils.equals(requestURI, loginApi)) {
            filterChain.doFilter(request, response);
            return;
        }
        String userInfoVal = getCookie("user_token", httpRequest);
        if (StringUtils.isEmpty(userInfoVal)) {
            setResponseRedirect(httpResponse);
            return;
        }
        SessionInfo sessionInfo = null;
        try {
            /*String realUserInfo =
                RSACoder.decryptByPublicKeyBySegment(userInfoVal.getBytes(StandardCharsets.UTF_8),
                    Constants.publicKey);*/
            String realUserInfo = AesUtils.decrypt(userInfoVal, Constants.CODE_KEY);
            sessionInfo = GsonTool.strToJavaBean(realUserInfo, SessionInfo.class);
            if (checkSessionParam(httpResponse, sessionInfo)) {
                return;
            }
        } catch (Exception ex) {
            LOGGER.error("loginFilter error ,msg = {}", ex.getMessage(), ex);
            setResponseRedirect(httpResponse);
            return;
        }
        UserInfoDO userInfoDO = getUserInfo(sessionInfo.getId());
        if (userInfoDO == null) {
            LOGGER.error("loginFilter error ,can not find user by id , {}", GsonTool.toJsonStringIgnoreNull(userInfoDO));
            setResponseRedirect(httpResponse);
            return;
        }
        SessionThreadLocalService.setRequest(httpRequest);
        SessionThreadLocalService.setSession(sessionInfo);
        try {
            filterChain.doFilter(request, response);
            return;
        } catch (Exception ex) {
            LOGGER.error("request error {}", ex.getMessage(), ex);
            throw ex;
        } finally {
            ThreadLocalManager.getInstance().removeThreadLocal();
        }
    }

    private UserInfoDO getUserInfo(Long id) {
        Result<UserInfoDO> result = userInfoService.findUserById(id);
        return result.getData();
    }

    private boolean checkSessionParam(HttpServletResponse httpResponse, SessionInfo sessionInfo) throws IOException {
        if (sessionInfo == null) {
            setResponseRedirect(httpResponse);
            return true;
        }
        if (sessionInfo.getId() == null) {
            setResponseRedirect(httpResponse);
            return true;
        }
        if (sessionInfo.getUserName() == null) {
            setResponseRedirect(httpResponse);
            return true;
        }
        if (sessionInfo.getLastTime() == null) {
            setResponseRedirect(httpResponse);
            return true;
        }
        if (System.currentTimeMillis() - sessionInfo.getLastTime() > 24 * 3600 * 1000) {
            setResponseRedirect(httpResponse);
            return true;
        }
        return false;
    }

    private void setResponseRedirect(HttpServletResponse httpResponse) throws IOException {
        httpResponse.setStatus(200);
        Result result = Result.getFail("-999", "redirect");
        httpResponse.getWriter().write(GsonTool.toJsonStringIgnoreNull(result));
        httpResponse.setContentType("application/json; charset=UTF-8");
        httpResponse.setHeader("Redirect", "true");
        httpResponse.setHeader("RedirectUrl", loginURL);
        httpResponse.flushBuffer();
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }

    private String getCookie(String key, HttpServletRequest httpServletRequest) {
        Cookie[] cookies = httpServletRequest.getCookies();
        if (cookies == null) {
            return null;
        }
        for (Cookie cookie : cookies) {
            if (StringUtils.equals(key, cookie.getName())) {
                return cookie.getValue();
            }
        }
        return null;
    }

    /*public static void main(String[] args) throws Exception {
        String val
            = "WhdYmQ3j9nHRVETCVOMC7jTBKlWq5Jog2v%2F4dwqYh%2BAY6ZDIUNBeZPkmpMA6x44fe0zmtgtM4c6Q29tlP"
            + "%2FUxLxsJ7btGlUMleGRT73y7qTHg69fV8FUkALs1BY8UDdgSLPIlJKztx%2BcYOaW"
            + "%2BOsh51THf4ZBIKGeE8UvozUG3pzvM0gy3x72FxWy0jrMazGqU4w8RTTSTEBIUIB44N%2FD1085nG%2BiGGH%2B4D2ABOprqUjY%3D";
        System.out.println(AesUtils.decryptByAES(val));
    }*/
}
